﻿#region License Info
//Component of Cronos Package, http://www.codeplex.com/cronos
//Copyright (C) 2009 Anthony Brockwell

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#endregion


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.Windows.Forms;
using ABMath.ModelFramework.Data;
using ABMath.ModelFramework.Visuals;
using ExtraControlLibrary.Forms;
using MathNet.Numerics.LinearAlgebra;
using PdfSharp;
using PdfSharp.Drawing;
using PdfSharp.Pdf;

namespace ExtraControlLibrary.VisualControls
{
    /// <summary>
    /// this class displays either a univariate or multivariate time series
    /// </summary>
    public partial class TSPlotControl : UserControl, IUpdateable
    {
        private int activeComponent = 0;
        private TSPlotVisual tspv;

        private bool showLag0;
        public bool ShowLag0
        { 
            get { return showLag0;}
            set
            {
                showLag0 = value;
                acfPlot.ShowLag0 = value;
                pacfPlot.ShowLag0 = value;
                DataHasChanged();
            }
        }

        private void DrawACFPACF()
        {
            // and then plot the acf and pacf
            int idx = activeComponent;
            int numForBands = tspv.NumObs[idx];
            if (tspv.TheObject as Longitudinal != null)
                numForBands = 0;
            acfPlot.SetACF(tspv.Lags, tspv.acfData[idx], numForBands);
            pacfPlot.SetACF(tspv.Lags, tspv.pacfData[idx], numForBands);

            acfPlot.Refresh();
            pacfPlot.Refresh();            
        }

        private void ChangeActiveSeries()
        {
            if (tspv == null)
                return;

            // plot the time series itself
            tsPlotBox.Title = tspv.BuildTitle(activeComponent);
            tsPlotBox.MultivariateActiveSeries = activeComponent;

            // and then plot the acf and pacf
            DrawACFPACF();

            tsPlotBox.Refresh();
        }

        private void DrawPlots()
        {
            if (tspv == null)
                return;

            // plot the time series itself
            tsPlotBox.Clear(false);
            foreach (var ts in tspv.tsData)
                tsPlotBox.AddSeries(ts, false);
            tsPlotBox.ScanData();
            tsPlotBox.Title = tspv.BuildTitle(activeComponent);

            // and then plot the acf and pacf
            DrawACFPACF();

            tsPlotBox.Refresh();
        }

        public void SetVisual(TSPlotVisual tspv)
        {
            this.tspv = tspv;
            if (tspv != null)
                tspv.AssociatedControl = this;
            else
                tsPlotBox.Clear(true);

            activeComponent = 0;
            DataHasChanged();
        }

        public TSPlotControl()
        {
            InitializeComponent();
            tspv = null;
        }

        public TSPlotControl(TSPlotVisual tspv)
        {
            InitializeComponent();
            SetVisual(tspv);
        }

        private void plotBox_RegionSelectEvent(object sender, TSPlotBox.RegionSelectArgs e)
        {
            // zoom in
            tsPlotBox.SetXRange(new Vector(new[] { e.x1, e.x2 }));
            tsPlotBox.Refresh();
        }

        private void plotBox_MouseClick(object sender, MouseEventArgs e)
        {
            if (tspv == null)
                return;

            if (e.Button == MouseButtons.Right)
            {
                // select from a drop-down menu
                var options = new List<string>();
                options.Add("Edit Title/Description");
                options.Add("Copy TS to Clipboard");
                options.Add("Copy TS to Clipboard, without Dates");
                options.Add("Save TS to File");
                options.Add("Copy Plot to Clipboard");
                options.Add("Export Plot to PDF File");
                options.Add("Toggle Multivariate Common Scale Mode");
                Point newLocation = PointToScreen(e.Location);
                var m = new DropMenuForm(newLocation, options);
                m.ShowDialog();
                {
                    switch (m.SelectedIndex)
                    {
                        case -1: // no selection
                            break;
                        case 0: // edit title/description
                            ChangeTitleOrDescription();
                            break;
                        case 1: // copy to clipboard
                            CopyToClipboard();
                            break;
                        case 2: // copy to clipboard w/out dates
                            CopyToClipboardWithoutDates();
                            break;
                        case 3: // save to file
                            SaveTSToFile();
                            break;
                        case 4: // copy plot to clipboard
                            CopyPlotToClipboard();
                            break;
                        case 5: // copy plot to clipboard
                            ExportPlotToPDFFile();
                            break;
                        case 6: // toggle MV common scale
                            tsPlotBox.MultivariateCommonScale = !tsPlotBox.MultivariateCommonScale;
                            tsPlotBox.Refresh();
                            break;
                    }
                }
            }
        }

        private void ChangeTitleOrDescription()
        {
            if (tspv == null)
                return;

            var td = new TitleDescriptionDialog(true) { StartPosition = FormStartPosition.CenterParent };
            var ts = tspv.tsData[activeComponent];
            td.Title = ts.Title;
            td.Description = ts.Description;
            if (td.ShowDialog() == DialogResult.OK)
            {
                ts.Title = td.Title;
                ts.Description = td.Description;
            }
        }

        private void SaveTSToFile()
        {
            if (tspv == null)
                return;

            // get file name
            var saveDialog = new SaveFileDialog();
            saveDialog.Filter = "Cronos TS File (*.cts)|*.cts" + "|Delimited Text Files (*.tsv,*.csv)|*.?sv" + "|All Files (*.*)|*.*";

            if (saveDialog.ShowDialog() == DialogResult.OK)
            {
                if (saveDialog.FileName.EndsWith(".cts", true, CultureInfo.CurrentCulture))
                    tspv.SaveToFile(saveDialog.FileName);
                else               
                    MessageBox.Show("Data not saved.  In this version, save file must end with .cts extension.", "Error");
            }
        }

        private void ExportPlotToPDFFile()
        {
            if (tspv == null)
                return;

            // get file name
            var saveDialog = new SaveFileDialog();
            saveDialog.Filter = "PDF Files (*.pdf)|*.pdf" + "|All Files (*.*)|*.*";

            // use pdfsharp
            if (saveDialog.ShowDialog() == DialogResult.OK)
            {
                double scale = 1.0;
                var document = new PdfDocument(saveDialog.FileName);
                var page = document.AddPage();
                page.Orientation = PageOrientation.Landscape;
                page.Width *= scale;
                page.Height *= scale;
                XGraphics gfx = XGraphics.FromPdfPage(page);
                tsPlotBox.CreatePartition(new Rectangle(0, 0, (int) page.Width, (int) page.Height));
                tsPlotBox.RenderToXGraphics(gfx, (int) Math.Floor(28*scale), (int) Math.Floor(16*scale));   // 16, 12
                document.Close();
            }
        }

        private void CopyToClipboard()
        {
            if (tspv == null)
                return;
            tspv.CopyToClipboard(true, false);
        }

        private void CopyPlotToClipboard()
        {
            if (tspv == null)
                return;

            // try graphics object from bitmap
            Bitmap bmp = new Bitmap(1200, 850, PixelFormat.Format32bppArgb);
            Graphics g = Graphics.FromImage(bmp);
            tsPlotBox.CreatePartition(new Rectangle(0, 0, 1200, 850));
            tsPlotBox.RenderToGraphics(g, 18, 15);
            Clipboard.SetImage(bmp);
        }

        private void CopyToClipboardWithoutDates()
        {
            if (tspv == null)
                return;
            tspv.CopyToClipboard(false, false);
        }

        private void vTSScrollBar_ValueChanged(object sender, EventArgs e)
        {
            if (tspv == null)
                return;
            if (tspv.tsData == null)
                return;
            if (tspv.tsData.Count == 0)
                return;
            if (activeComponent == vTSScrollBar.Value)
                return; // no change

            activeComponent = vTSScrollBar.Value;
            tsPlotBox.MultivariateActiveSeries = activeComponent;

            ChangeActiveSeries();
        }

        public void DataHasChanged()
        {
            if (tspv == null)
                return;
            if (tspv.tsData == null)
                return;
            if (tspv.tsData.Count == 0)
                return;

            vTSScrollBar.Minimum = 0;
            vTSScrollBar.Maximum = tspv.tsData.Count - 1;
            vTSScrollBar.SmallChange = 1;
            vTSScrollBar.LargeChange = 1;
            vTSScrollBar.Value = 0;

            DrawPlots();
        }
    }
}